package org.fpp.sqlparse;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.UnsupportedStatement;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.alter.AlterExpression;
import net.sf.jsqlparser.statement.alter.AlterOperation;
import net.sf.jsqlparser.statement.comment.Comment;
import net.sf.jsqlparser.statement.create.index.CreateIndex;
import net.sf.jsqlparser.statement.create.table.*;
import net.sf.jsqlparser.statement.drop.Drop;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.fpp.sqlparse.DataModelConstant.*;
import static cn.hutool.core.text.CharSequenceUtil.SPACE;
import static net.sf.jsqlparser.statement.alter.AlterOperation.*;
import static net.sf.jsqlparser.statement.alter.AlterOperation.COMMENT;
import static org.fpp.sqlparse.DataModelConstant.UNIQUE;

/**
 * @author pengpeng_fu@infinova.com.cn
 * @date 2023-12-22 15:44
 */
public class SqlParseSupport implements ISqlParseSupport {

    @Override
    public void checkSql(String sql){
        if(StrUtil.isNotBlank(sql)) {
            String[] split = sql.split(";");
            for (String string : split) {
                if (StrUtil.isBlank(string.trim())) {
                    continue;
                }
                try {
                    CCJSqlParserUtil.parse(string);
                } catch (JSQLParserException e) {
                    throw new IllegalStateException("错误的sql:"+string);
                }
            }
        }
    }

    @Override
    public Map<String, TableInfo> analysisDdl(String sql) {
        String[] split = sql.split(";");
        Map<String, TableInfo> tableInfoMap = new HashMap<>();
        for (String string : split) {
            try {
                if (StrUtil.isBlank(string.trim())) {
                    continue;
                }
                Statement statement = CCJSqlParserUtil.parse(string);
                if (statement instanceof CreateTable) {
                    CreateTable createTable = (CreateTable) statement;
                    List<ColumnDefinition> columnDefinitions = createTable.getColumnDefinitions();
                    String tableName = createTable.getTable().getName();
                    tableInfoMap.putIfAbsent(tableName, new TableInfo());
                    TableInfo tableInfo = tableInfoMap.get(tableName);
                    fillTableColumn(createTable, columnDefinitions, tableInfo);
                    List<Index> indexes = createTable.getIndexes();
                    fillPrimaryKey(tableInfo, indexes);
                    tableInfo.setName(tableName);
                } else if (statement instanceof Comment) {
                    Comment comment = (Comment) statement;
                    Table table = comment.getTable();
                    Column column = comment.getColumn();
                    String tableName = Optional.ofNullable(table).map(Table::getName).orElseGet(() -> column.getTable().getName());
                    tableInfoMap.putIfAbsent(tableName, new TableInfo());
                    TableInfo tableInfo = tableInfoMap.get(tableName);
                    if (null == column) {
                        //说明是表注释
                        tableInfo.setComment(comment.getComment().getValue());
                    } else {
                        List<TableInfo.ColumnInfo> columnList = tableInfo.getColumnList();
                        for (TableInfo.ColumnInfo columnInfo : columnList) {
                            if (columnInfo.getName().equals(column.getColumnName())) {
                                columnInfo.setComment(StrUtil.strip(comment.getComment().getValue(),"'"));
                            }
                        }
                    }
                } else if (statement instanceof CreateIndex) {
                    CreateIndex createIndex = (CreateIndex) statement;
                    Table table = createIndex.getTable();
                    String tableName = table.getName();
                    tableInfoMap.putIfAbsent(tableName, new TableInfo());
                    TableInfo tableInfo = tableInfoMap.get(tableName);
                    Index index = createIndex.getIndex();
                    if (null == tableInfo.getIndexList()) {
                        tableInfo.setIndexList(new ArrayList<>());
                    }
                    TableInfo.IndexInfo indexInfo = TableInfo.IndexInfo.defaultObj();
                    indexInfo.setName(index.getName());
                    indexInfo.setColumnNames(index.getColumnsNames());
                    indexInfo.setComment(index.getName());
                    indexInfo.setUniqueKey(UNIQUE.equals(index.getType()));
                    tableInfo.getIndexList().add(indexInfo);
                } else if (statement instanceof Alter){
                    Alter alter = (Alter) statement;
                    Table table = alter.getTable();
                    String tableName = table.getName();
                    tableInfoMap.putIfAbsent(tableName, new TableInfo());
                    TableInfo tableInfo = tableInfoMap.get(tableName);
                    if(alter.getAlterExpressions().stream().anyMatch(s-> COMMENT.equals(s.getOperation()))){
                        alter.getAlterExpressions().stream().filter(s-> COMMENT.equals(s.getOperation()))
                                .findFirst().ifPresent(s->{
                                    String commentText = s.getCommentText();
                                    tableInfo.setComment(StrUtil.strip(commentText, "'"));
                                });
                    }
                }
            } catch (Exception warn) {
                throw new IllegalStateException("错误的sql:"+string);
            }
        }
        return tableInfoMap;
    }

    private void fillTableColumn(CreateTable createTable, List<ColumnDefinition> columnDefinitions, TableInfo tableInfo) {
        if (CollUtil.isNotEmpty(createTable.getColumnDefinitions())) {
            if (null == tableInfo.getColumnList()) {
                tableInfo.setColumnList(new ArrayList<>());
            }
            for (ColumnDefinition columnDefinition : columnDefinitions) {
                TableInfo.ColumnInfo columnInfo = TableInfo.ColumnInfo.defaultObj();
                columnInfo.setName(columnDefinition.getColumnName());
                ColDataType colDataType = columnDefinition.getColDataType();
                columnInfo.setDataType(colDataType.getDataType());
                if (CollUtil.contains(STRING_TYPE_LIST,s->s.equalsIgnoreCase(colDataType.getDataType()))) {
                    if (CollUtil.isNotEmpty(colDataType.getArgumentsStringList())) {
                        String argument = colDataType.getArgumentsStringList().get(0);
                        if (NumberUtil.isNumber(argument)) {
                            columnInfo.setLength(Integer.valueOf(argument));
                        }
                    }
                }
                tableInfo.getColumnList().add(columnInfo);
                List<String> columnSpecs = columnDefinition.getColumnSpecs();
                if (CollUtil.isNotEmpty(columnSpecs)) {
                    fillColumn(columnInfo, columnSpecs);
                }
            }
        }
    }

    private void fillPrimaryKey(TableInfo tableInfo, List<Index> indexes) {
        if(CollUtil.isNotEmpty(indexes)){
            for(Index index: indexes){
                if(PRIMARY_KEY.equals(index.getType())){
                    List<String> columnsNames = Optional.ofNullable(index.getColumnsNames())
                            .orElse(Collections.emptyList());
                    for(TableInfo.ColumnInfo columnInfo: tableInfo.getColumnList()){
                        if(columnsNames.contains(columnInfo.getName())){
                            columnInfo.setPrimaryKey(true);
                        }
                    }
                }
            }
        }
    }

    private static void fillColumn(TableInfo.ColumnInfo columnInfo, List<String> columnSpecs) {
        try {
            //包含注释
            if(columnSpecs.stream().anyMatch(DataModelConstant.COMMENT::equalsIgnoreCase)){
                //获取注释
                int commentIndex = ListUtil.lastIndexOf(columnSpecs, DataModelConstant.COMMENT::equalsIgnoreCase);
                if(-1!=commentIndex){
                    columnInfo.setComment(StrUtil.strip(columnSpecs.get(commentIndex+1),"'"));
                }
                //去除注释
                List<String> sub = ListUtil.sub(columnSpecs, 0, commentIndex);
                doFillColumnIgnoreComment(columnInfo,sub);
            }else{
                //是否为空判断
                doFillColumnIgnoreComment(columnInfo, columnSpecs);
            }
        }catch (Exception warn){
            System.err.println("填充字段失败"+warn.getMessage());
        }
    }

    private static void doFillColumnIgnoreComment(TableInfo.ColumnInfo columnInfo, List<String> columnSpecs) {
        columnInfo.setNullable(!StrUtil.containsIgnoreCase(String.join("", columnSpecs), NOTNULL));
        //获取默认值
        int i = ListUtil.lastIndexOf(columnSpecs, DEFAULT::equalsIgnoreCase);
        if(-1!=i){
            String defaultValue = columnSpecs.get(i + 1);
            columnInfo.setDefaultValue(StrUtil.strip(defaultValue, "'"));
        }
        //是否自增
        int commentIndex = ListUtil.lastIndexOf(columnSpecs, AUTO_INCREMENT::equalsIgnoreCase);
        if(commentIndex>0){
            columnInfo.setAutoIncrement(true);
        }
        int commentSerialIndex = ListUtil.lastIndexOf(columnSpecs, SERIAL::equalsIgnoreCase);
        if(commentSerialIndex>0){
            columnInfo.setAutoIncrement(true);
        }
    }

    @Override
    public String buildDdlSql(DbType dbType, TableInfo tableInfo){
        StringBuilder stringBuilder=new StringBuilder();
        Table table = new Table(tableInfo.getName());
        buildDdlTable(dbType, tableInfo, stringBuilder, table);
        buildDdlComment(dbType, tableInfo, table, stringBuilder);
        buildDdlIndex(tableInfo, table, stringBuilder);
        return stringBuilder.toString();
    }

    private void buildDdlTable(DbType dbType, TableInfo tableInfo, StringBuilder stringBuilder, Table table) {
        // 生成 DDL 语句
        CreateTable createTable = new CreateTable();
        createTable.setTable(table);
        List<TableInfo.ColumnInfo> columnList = tableInfo.getColumnList();
        boolean notEmptyColumn = CollUtil.isNotEmpty(columnList);
        if(notEmptyColumn) {
            for(TableInfo.ColumnInfo columnInfo: columnList) {
                // 添加列到表中
                ColumnDefinition columnDefinition = new ColumnDefinition();
                columnDefinition.setColumnName(columnInfo.getName());
                ColDataType colDataType = new ColDataType();
                String dataType = columnInfo.getDataType();
                colDataType.setDataType(dataType);
                if(null!=columnInfo.getLength()) {
                    colDataType.setArgumentsStringList(Collections.singletonList(String.valueOf(columnInfo.getLength())));
                }
                columnDefinition.setColDataType(colDataType);
                if(BooleanUtil.isFalse(columnInfo.getNullable())){
                    columnDefinition.addColumnSpecs(NOT,NULL);
                }
                if(dbType.sameMysql()&&BooleanUtil.isTrue(columnInfo.getAutoIncrement())){
                    columnDefinition.addColumnSpecs(AUTO_INCREMENT);
                }
                appendColumnDefault(columnInfo, columnDefinition);
                if(dbType.sameMysql()&&StrUtil.isNotBlank(columnInfo.getComment())){
                    columnDefinition.addColumnSpecs(DataModelConstant.COMMENT);
                    columnDefinition.addColumnSpecs(new StringValue(columnInfo.getComment()).toString());
                }
                createTable.addColumnDefinitions(columnDefinition);
            }

            List<Index.ColumnParams> primaryKeyColumns = columnList.stream()
                    .filter(s->BooleanUtil.isTrue(s.getPrimaryKey()))
                    .map(s -> new Index.ColumnParams(s.getName()))
                    .collect(Collectors.toList());
            if(CollUtil.isNotEmpty(primaryKeyColumns)){
                NamedConstraint index=new NamedConstraint();
                index.setType(PRIMARY_KEY);
                index.setColumns(primaryKeyColumns);
                createTable.setIndexes(new ArrayList<>());
                createTable.getIndexes().add(index);
            }
        }

        stringBuilder.append(createTable).append(";");
    }

    private void appendColumnDefault(TableInfo.ColumnInfo columnInfo, ColumnDefinition columnDefinition) {
        if(StrUtil.isNotBlank(columnInfo.getDefaultValue())){
            columnDefinition.addColumnSpecs(DEFAULT);
            if(CollUtil.contains(STRING_TYPE_LIST, s->s.equalsIgnoreCase(columnInfo.getDataType()))){
                columnDefinition.addColumnSpecs(new StringValue(columnInfo.getDefaultValue()).toString());
            }else{
                columnDefinition.addColumnSpecs(columnInfo.getDefaultValue());
            }
        }
    }

    private void buildDdlIndex(TableInfo tableInfo, Table table, StringBuilder stringBuilder) {
        List<TableInfo.IndexInfo> indexList = tableInfo.getIndexList();
        if(CollUtil.isNotEmpty(indexList)){
            for(TableInfo.IndexInfo indexInfo:indexList){
                CreateIndex createIndex=new CreateIndex();
                createIndex.setTable(table);
                Index index=new Index();
                if(BooleanUtil.isTrue(indexInfo.getUniqueKey())) {
                    index.setType(UNIQUE);
                }
                index.setColumnsNames(indexInfo.getColumnNames());
                index.setName(indexInfo.getName());
                createIndex.setIndex(index);
                stringBuilder.append(createIndex).append(";");
            }
        }
    }

    private void buildDdlComment(DbType dbType, TableInfo tableInfo, Table table, StringBuilder stringBuilder) {
        List<TableInfo.ColumnInfo> columnList = tableInfo.getColumnList();
        boolean notEmptyColumn = CollUtil.isNotEmpty(columnList);
        if(dbType.sameMysql()&&StrUtil.isNotBlank(tableInfo.getComment())){
            appendMysqlTableComment(tableInfo, table, stringBuilder);
        }

        if(dbType.samePostgresql()&& notEmptyColumn){
            for(TableInfo.ColumnInfo columnInfo: columnList) {
                if(StrUtil.isNotBlank(columnInfo.getComment())) {
                    Comment comment = new Comment();
                    comment.setTable(table);
                    Column column = new Column();
                    column.setColumnName(columnInfo.getName());
                    comment.setColumn(column);
                    comment.setComment(new StringValue(columnInfo.getComment()));
                    stringBuilder.append(comment).append(";");
                }
            }
        }
    }

    private void appendMysqlTableComment(TableInfo tableInfo, Table table, StringBuilder stringBuilder) {
        Alter alter=new Alter();
        alter.setTable(table);
        alter.setAlterExpressions(new ArrayList<>());
        AlterExpression alterExpression = new AlterExpression();
        alterExpression.setOperation(COMMENT);
        alterExpression.setCommentText(new StringValue(tableInfo.getComment()).toString());
        alter.getAlterExpressions().add(alterExpression);
        stringBuilder.append(alter).append(";");
    }

    @Override
    public String incrementalUpdateSql(DbType dbType, TableInfo oldTableInfo, TableInfo newTableInfo){
        if(oldTableInfo.equals(newTableInfo)){
            return null;
        }
        StringBuilder stringBuilder=new StringBuilder();
        Table tableOld=new Table(oldTableInfo.getName());
        Table tableUpdated = dealTableNameChange(oldTableInfo, newTableInfo, stringBuilder, tableOld);
        dealCommentChange(dbType, oldTableInfo, newTableInfo, tableUpdated, stringBuilder);
        dealColumnChange(dbType, oldTableInfo, newTableInfo, tableUpdated, stringBuilder);
        dealIndexChange(dbType, oldTableInfo, newTableInfo,tableUpdated, stringBuilder);
        return stringBuilder.toString();
    }

    private Table dealTableNameChange(TableInfo oldTableInfo, TableInfo newTableInfo, StringBuilder stringBuilder, Table tableOld) {
        Table tableUpdated= tableOld;
        //是否更新表名
        if(!oldTableInfo.getName().equals(newTableInfo.getName())){
            Alter alter=new Alter();
            alter.setTable(tableOld);
            alter.setAlterExpressions(new ArrayList<>());
            AlterExpression alterExpression = new AlterExpression();
            alterExpression.setOperation(RENAME_TABLE);
            alterExpression.setNewTableName(newTableInfo.getName());
            alter.getAlterExpressions().add(alterExpression);
            stringBuilder.append(alter).append(";");
            tableUpdated=new Table(newTableInfo.getName());
        }
        return tableUpdated;
    }

    private void dealCommentChange(DbType dbType, TableInfo oldTableInfo, TableInfo newTableInfo, Table tableUpdated, StringBuilder stringBuilder) {
        //是否更新表注释
        if(!StrUtil.equals(oldTableInfo.getComment(),newTableInfo.getComment())){
            if(dbType.sameMysql()) {
                appendMysqlTableComment(newTableInfo, tableUpdated, stringBuilder);
            }else if(dbType.samePostgresql()){
                Comment comment = new Comment();
                comment.setTable(tableUpdated);
                comment.setComment(new StringValue(newTableInfo.getComment()));
                stringBuilder.append(comment).append(";");
            }
        }
    }

    private void dealIndexChange(DbType dbType, TableInfo oldTableInfo, TableInfo newTableInfo, Table tableUpdate, StringBuilder stringBuilder) {
        //1 是否更新字段名
        //2 是否更新字段注释
        //3 是否更新字段类型
        Map<IndexSerializable.OperationWrapper<TableInfo.IndexInfo>, TableInfo.IndexInfo> changeIndex =
                IndexSerializable.getChange(oldTableInfo.getIndexList(), newTableInfo.getIndexList());
        //是否更新索引信息
        //1 是否更新索引名
        changeIndex.forEach((op,obj)->{
            switch (op.getOperation()){
                case DELETE:
                    if(dbType.sameMysql()){
                        Drop drop = new Drop();
                        drop.setType(INDEX);
                        drop.setName(new Table(obj.getName()));
                        drop.addParameters(ON, tableUpdate.getName());
                        stringBuilder.append(drop).append(";");
                    }else if(dbType.samePostgresql()) {
                        Drop drop = new Drop();
                        drop.setType(INDEX);
                        drop.setName(new Table(obj.getName()));
                        stringBuilder.append(drop).append(";");
                    }
                    break;
                case UPDATE:
                    if(dbType.sameMysql()){
                        Drop drop = new Drop();
                        drop.setType(INDEX);
                        drop.setName(new Table(op.getObject().getName()));
                        drop.addParameters(ON, tableUpdate.getName());
                        stringBuilder.append(drop).append(";");
                        CreateIndex createIndex=new CreateIndex();
                        Index index=new Index();
                        index.setName(obj.getName());
                        if(BooleanUtil.isTrue(obj.getUniqueKey())){
                            index.setType(UNIQUE);
                        }
                        index.setColumns(obj.getColumnNames()
                                .stream()
                                .map(Index.ColumnParams::new)
                                .collect(Collectors.toList()));
                        createIndex.setTable(tableUpdate);
                        createIndex.setIndex(index);
                        stringBuilder.append(createIndex).append(";");
                    }else if(dbType.samePostgresql()) {
                        if(!op.getObject().getName().equals(obj.getName())){
                            List<String> list=new ArrayList<>();
                            list.add(ALTER.name());
                            list.add(INDEX);
                            list.add(op.getObject().getName());
                            list.add(RENAME.name().toLowerCase());
                            list.add(TO);
                            list.add(obj.getName());
                            UnsupportedStatement unsupportedStatement=new UnsupportedStatement(list);
                            stringBuilder.append(unsupportedStatement).append(";");
                        }
                    }
                    break;
                case INSERT:
                    CreateIndex createIndex=new CreateIndex();
                    Index index=new Index();
                    index.setName(obj.getName());
                    if(BooleanUtil.isTrue(obj.getUniqueKey())){
                        index.setType(UNIQUE);
                    }
                    index.setColumns(obj.getColumnNames()
                            .stream()
                            .map(Index.ColumnParams::new)
                            .collect(Collectors.toList()));
                    createIndex.setTable(tableUpdate);
                    createIndex.setIndex(index);
                    stringBuilder.append(createIndex).append(";");
                    break;
                default:
                    break;
            }
        });
    }

    private void dealColumnChange(DbType dbType, TableInfo oldTableInfo, TableInfo newTableInfo, Table tableUpdated, StringBuilder stringBuilder) {
        Map<IndexSerializable.OperationWrapper<TableInfo.ColumnInfo>, TableInfo.ColumnInfo> changeColumn =
                IndexSerializable.getChange(oldTableInfo.getColumnList(), newTableInfo.getColumnList());
        changeColumn.forEach((op, newObj)->{
            switch (op.getOperation()){
                case DELETE:
                    Alter alter = new Alter();
                    alter.setTable(tableUpdated);
                    alter.setAlterExpressions(new ArrayList<>());
                    AlterExpression alterExpression = new AlterExpression();
                    alterExpression.setOperation(AlterOperation.DROP);
                    alterExpression.setColumnName(newObj.getName());
                    alter.getAlterExpressions().add(alterExpression);
                    stringBuilder.append(alter).append(";");
                    break;
                case UPDATE:
                    if(dbType.sameMysql()) {
                        Alter alterUpdate = new Alter();
                        alterUpdate.setTable(tableUpdated);
                        alterUpdate.setAlterExpressions(new ArrayList<>());
                        AlterExpression alterExpressionUpdate = new AlterExpression();
                        alterExpressionUpdate.setOperation(CHANGE);
                        alterExpressionUpdate.setColumnOldName(op.getObject().getName());
                        AlterExpression.ColumnDataType colDataType=new AlterExpression.ColumnDataType(false);
                        colDataType.setColumnName(newObj.getName());
                        ColDataType colDataTypeObj = new ColDataType();
                        colDataTypeObj.setDataType(newObj.getDataType());
                        if(null!=newObj.getLength()){
                            colDataTypeObj.addArgumentsStringList(String.valueOf(newObj.getLength()));
                        }
                        colDataType.setColDataType(colDataTypeObj);
                        if(StrUtil.isNotBlank(newObj.getDefaultValue())){
                            colDataType.addColumnSpecs(DEFAULT);
                            if(CollUtil.contains(STRING_TYPE_LIST,s->s.equalsIgnoreCase(newObj.getDataType()))){
                                colDataType.addColumnSpecs("'" +newObj.getDefaultValue()+ "'");
                            }else{
                                colDataType.addColumnSpecs(newObj.getDefaultValue());
                            }
                        }
                        if(BooleanUtil.isTrue(newObj.getNullable())){
                            colDataType.addColumnSpecs(NULL);
                        }else{
                            colDataType.addColumnSpecs(NOT,NULL);
                        }
                        if(StrUtil.isNotBlank(newObj.getComment())){
                            colDataType.addColumnSpecs(DataModelConstant.COMMENT);
                            colDataType.addColumnSpecs(new StringValue(newObj.getComment()).toString());
                        }
                        alterExpressionUpdate.addColDataType(colDataType);
                        alterUpdate.getAlterExpressions().add(alterExpressionUpdate);
                        stringBuilder.append(alterUpdate).append(";");
                    } else if (dbType.samePostgresql()) {
                        //如果字段名有变动
                        String updateColumnName = op.getObject().getName();
                        if (!StrUtil.equals(op.getObject().getName(),newObj.getName())) {
                            Alter alterUpdate = new Alter();
                            alterUpdate.setTable(tableUpdated);
                            alterUpdate.setAlterExpressions(new ArrayList<>());
                            AlterExpression alterExpressionUpdate = new AlterExpression();
                            alterExpressionUpdate.setOperation(RENAME);
                            alterExpressionUpdate.setColumnOldName(op.getObject().getName());
                            alterExpressionUpdate.setColumnName(newObj.getName());
                            alterUpdate.getAlterExpressions().add(alterExpressionUpdate);
                            stringBuilder.append(alterUpdate).append(";");
                            updateColumnName = newObj.getName();
                        }
                        //备注不一样
                        if (!StrUtil.equals(op.getObject().getComment(),newObj.getComment())) {
                            Comment comment = new Comment();
                            comment.setColumn(new Column().withTable(tableUpdated).withColumnName(updateColumnName));
                            comment.setComment(new StringValue(newObj.getComment()));
                            stringBuilder.append(comment).append(";");
                        }
                        //字段类型不一样
                        if ((!StrUtil.equals(op.getObject().getDataType(),newObj.getDataType()))
                                ||(!ObjectUtil.equals(op.getObject().getLength(),newObj.getLength()))) {
                            Alter alterUpdate = new Alter();
                            alterUpdate.setTable(tableUpdated);
                            alterUpdate.setAlterExpressions(new ArrayList<>());
                            AlterExpression alterExpressionUpdate = new AlterExpression();
                            alterExpressionUpdate.setOperation(ALTER);
                            alterExpressionUpdate.hasColumn(true);
                            AlterExpression.ColumnDataType colDataType = new AlterExpression.ColumnDataType(true);
                            colDataType.setColumnName(updateColumnName);
                            ColDataType colDataTypeObj = new ColDataType();
                            colDataTypeObj.setDataType(newObj.getDataType());
                            if (null != newObj.getLength()) {
                                colDataTypeObj.addArgumentsStringList(String.valueOf(newObj.getLength()));
                            }
                            colDataType.setColDataType(colDataTypeObj);
                            colDataType.addColumnSpecs(USING, updateColumnName+"::"+newObj.getDataType());
                            alterExpressionUpdate.addColDataType(colDataType);
                            alterUpdate.getAlterExpressions().add(alterExpressionUpdate);
                            stringBuilder.append(alterUpdate).append(";");
                        }
                        //默认值不一样
                        if (!op.getObject().getDefaultValue().equals(newObj.getDefaultValue())) {
                            Alter alterUpdate = new Alter();
                            alterUpdate.setTable(tableUpdated);
                            AlterExpression alterExpressionUpdate = new AlterExpression();
                            alterExpressionUpdate.setOperation(ALTER);
                            AlterExpression.ColumnDataType colDataType = new AlterExpression.ColumnDataType(false);
                            ColDataType colDataTypeObj = new ColDataType();
                            colDataTypeObj.setDataType(SET);
                            colDataType.setColDataType(colDataTypeObj);
                            colDataType.setColumnName(updateColumnName);
                            if(CollUtil.contains(STRING_TYPE_LIST,s->s.equalsIgnoreCase(newObj.getDataType()))){
                                colDataType.addColumnSpecs(DEFAULT, new StringValue(newObj.getDefaultValue()).toString());
                            }else{
                                colDataType.addColumnSpecs(DEFAULT, newObj.getDefaultValue());
                            }
                            alterExpressionUpdate.addColDataType(colDataType);
                            alterUpdate.addAlterExpression(alterExpressionUpdate);
                            stringBuilder.append(alterUpdate).append(";");
                        }
                        //非空不一样
                        if (!ObjectUtil.equals(op.getObject().getNullable(),newObj.getNullable())) {
                            if(BooleanUtil.isTrue(newObj.getNullable())){
                                Alter alterUpdate = new Alter();
                                alterUpdate.setTable(tableUpdated);
                                alterUpdate.setAlterExpressions(new ArrayList<>());
                                AlterExpression alterExpressionUpdate = new AlterExpression();
                                alterExpressionUpdate.setOperation(UNSPECIFIC);
                                alterExpressionUpdate.setOptionalSpecifier(COLUMN+SPACE+updateColumnName+SPACE+DataModelConstant.DROP+SPACE_NOTNULL);
                                alterUpdate.getAlterExpressions().add(alterExpressionUpdate);
                                stringBuilder.append(alterUpdate).append(";");
                            }else{
                                Alter alterUpdate = new Alter();
                                alterUpdate.setTable(tableUpdated);
                                alterUpdate.setAlterExpressions(new ArrayList<>());
                                AlterExpression alterExpressionUpdate = new AlterExpression();
                                alterExpressionUpdate.setOperation(UNSPECIFIC);
                                alterExpressionUpdate.setOptionalSpecifier(COLUMN+SPACE+updateColumnName+SPACE+SET+SPACE_NOTNULL);
                                alterUpdate.getAlterExpressions().add(alterExpressionUpdate);
                                stringBuilder.append(alterUpdate).append(";");
                            }
                        }
                    }
                    break;
                case INSERT:
                    //字段声明
                    Alter alterAdd = new Alter();
                    alterAdd.setTable(tableUpdated);
                    alterAdd.setAlterExpressions(new ArrayList<>());
                    AlterExpression alterExpressionAdd = new AlterExpression();
                    alterExpressionAdd.setOperation(ADD);
                    AlterExpression.ColumnDataType columnDataType = new AlterExpression.ColumnDataType(false);
                    columnDataType.setColumnName(newObj.getName());
                    ColDataType colDataType = new ColDataType();
                    columnDataType.setColDataType(colDataType);
                    colDataType.setDataType(newObj.getDataType());
                    if(null!=newObj.getLength()) {
                        colDataType.setArgumentsStringList(Collections.singletonList(String.valueOf(newObj.getLength())));
                    }
                    appendColumnDefault(newObj, columnDataType);
                    if(BooleanUtil.isTrue(newObj.getNullable())){
                        columnDataType.addColumnSpecs(NULL);
                    }else{
                        columnDataType.addColumnSpecs(NOT,NULL);
                    }
                    if(StrUtil.isNotBlank(newObj.getComment())){
                        columnDataType.addColumnSpecs(DataModelConstant.COMMENT);
                        columnDataType.addColumnSpecs(new StringValue(newObj.getComment()).toString());
                    }
                    alterExpressionAdd.addColDataType(columnDataType);
                    alterAdd.getAlterExpressions().add(alterExpressionAdd);
                    stringBuilder.append(alterAdd).append(";");

                    //字段注释
                    if(dbType.samePostgresql()){
                        Comment comment = new Comment();
                        comment.setColumn(new Column().withTable(tableUpdated).withColumnName(newObj.getName()));
                        comment.setComment(new StringValue(newObj.getComment()));
                        stringBuilder.append(comment).append(";");
                    }

                    //添加主键
                    if(BooleanUtil.isTrue(newObj.getPrimaryKey())) {
                        Alter alterPrimaryKey = new Alter();
                        alterPrimaryKey.setTable(tableUpdated);
                        alterPrimaryKey.setAlterExpressions(new ArrayList<>());
                        AlterExpression alterExpressionComment = new AlterExpression();
                        alterExpressionComment.setOperation(ADD);
                        Index index=new Index();
                        index.setType(PRIMARY_KEY);
                        index.addColumns(new Index.ColumnParams(newObj.getName()));
                        alterExpressionComment.setIndex(index);
                        alterPrimaryKey.getAlterExpressions().add(alterExpressionComment);
                        stringBuilder.append(alterPrimaryKey).append(";");
                    }
                default:
                    break;
            }
        });
    }

    @Override
    public TableInfoDiff diff(TableInfo oldTableInfo, TableInfo newTableInfo){
        Map<IndexSerializable.OperationWrapper<TableInfo.ColumnInfo>, TableInfo.ColumnInfo> changeColumnMap =
                IndexSerializable.getChange(oldTableInfo.getColumnList(), newTableInfo.getColumnList());

        Map<IndexSerializable.OperationWrapper<TableInfo.IndexInfo>, TableInfo.IndexInfo> changeIndexMap =
                IndexSerializable.getChange(oldTableInfo.getIndexList(), newTableInfo.getIndexList());

        TableInfoDiff tableInfo=new TableInfoDiff();
        tableInfo.setChangeIndexMap(changeIndexMap);
        tableInfo.setChangeColumnMap(changeColumnMap);
        tableInfo.setOldComment(oldTableInfo.getComment());
        tableInfo.setNewComment(newTableInfo.getComment());
        tableInfo.setCommentUpdated(!StrUtil.equals(oldTableInfo.getComment(),newTableInfo.getComment()));
        tableInfo.setNewName(newTableInfo.getName());
        tableInfo.setOldName(oldTableInfo.getName());
        tableInfo.setNameUpdated(!StrUtil.equals(oldTableInfo.getName(),newTableInfo.getName()));
        return tableInfo;
    }
}
